/*
* Copyright (c) 2012 Kyle Hayward
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#pragma once

#include "Buffer.h"

namespace OptixDotNet 
{
	ref class OGLBuffer;

	/// <summary>
	/// Description data used to create a <see cref="OptixDotNet::OGLBuffer">OGLBuffer</see>.
	/// </summary>
	public value struct OGLBufferDesc
	{
		/// <summary>
		/// Width of the Buffer.
		/// </summary>
		Size Width;

		/// <summary>
		/// Height of the Buffer.
		/// </summary>
		Size Height;

		/// <summary>
		/// Depth of the Buffer.
		/// </summary>
		Size Depth;

		/// <summary>
		/// <see cref="OptixDotNet::BufferType">Type</see> of the Buffer.
		/// </summary>
		BufferType Type;

		/// <summary>
		/// <see cref="OptixDotNet::Format">Format</see> of the Buffer.
		/// </summary>
		OptixDotNet::Format Format;

		/// <summary>
		/// Size of the Type the buffer contains. Only needed for <see cref="OptixDotNet::Format::User">Format.User</see> formats.
		/// </summary>
		Size ElemSize;

		/// <summary>
		/// ID of the OpenGl resource used to create the OGLBuffer.
		/// </summary>
		unsigned int Resource;

		/// <summary>
		/// Gets a default OGLBufferDesc with safe initilaized values.
		/// Width = 1
		/// Height = 1
		/// Depth = 1
		/// Type = None
		/// Format = Unknown
		/// Resource = 0
		/// </summary>
		static property OGLBufferDesc Default
		{
			OGLBufferDesc get()
			{
				OGLBufferDesc desc = { 1, 1, 1, BufferType::None, OptixDotNet::Format::Unknown, 0, 0 };
				return desc;
			}
		}
	};

	/// <summary>
	/// Represents a buffer created from a OpenGl buffer object (e.g. PBO or VBO) resource. OpenGl buffer objects can be read and written to.
	/// <para>
	/// Once a OGLBuffer is created the resource is immutable, meaning its properties cannot be modified.
	/// You must unregister the Buffer in order to modify its properties.
	/// </para>
    /// </summary>
	public ref class OGLBuffer : public Buffer
	{
	public:
		/// <summary>
		/// Create a Buffer from an OpenGl buffer object resource.
		/// </summary>
		/// <param name="context">Optix context</param>
		/// <param name="desc">Description of the buffer</param>
		OGLBuffer( Context^ context, OGLBufferDesc desc );

		/// <summary>
		/// Declares a OpenGl buffer as immutable and accessible by OptiX.
		/// Once registered, the buffer's properties will not be able to be modified
		/// </summary>
		void Register();

		/// <summary>
		/// Declares a OpenGl buffer as mutable and inaccessible by OptiX.
		/// Once unregistered, the buffer's properties are able to be modified.
		/// The buffer must be re-registered once changes are done being made.
		/// </summary>
		void Unregister();

		/// <summary>
		/// Gets a the OpenGl Buffer Object ID.
		/// </summary>
		property unsigned int Resource
		{
			unsigned int get();
		}

	private:
		void Create( OGLBufferDesc% desc );
	};
}